home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / dos / fs / backup20.1 next >
Text File  |  1988-11-05  |  51KB  |  2,188 lines

  1. Path: xanth!nic.MR.NET!hal!cwjcc!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i052:  backup - file backup utility V2.01
  5. Message-ID: <10049@swan.ulowell.edu>
  6. Date: 4 Nov 88 22:20:16 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2177
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: dillon@postgres.berkeley.edu (Matt Dillon)
  12. Posting-number: Volume 2, Issue 52
  13. Archive-name: dos/fs/backup201.1
  14.  
  15. There are some serious bugs in backup/restore version V2.00.
  16. This is version 2.01, and fixes the following problems:
  17.     (1) Restore would not put files in the proper sub-directory
  18.     (2) Append mode for backup does not work
  19. These bugs were found by Jan Sven Trabandt.
  20.  
  21. #    This is a shell archive.
  22. #    Remove everything above and including the cut line.
  23. #    Then run the rest of the file through sh.
  24. #----cut here-----cut here-----cut here-----cut here----#
  25. #!/bin/sh
  26. # shar:    Shell Archiver
  27. #    Run the following text with /bin/sh to create:
  28. #    backup.c
  29. #    Makefile
  30. #    backup.doc
  31. # This archive created: Fri Nov  4 17:11:15 1988
  32. cat << \SHAR_EOF > backup.c
  33.  
  34. /*
  35.  * BACKUP.C
  36.  *
  37.  * (C)Copyright 1986-88, Matthew Dillon, All Rights Reserved.
  38.  * Permission is granted to distribute for non-profit only.
  39.  *
  40.  *  Thanks to Jan Sven Trabandt for finding some major bugs!
  41.  *
  42.  * This program will backup a filesystem or directory, creating a single
  43.  * output file which can later be RESTORE'd from.  It is a quick way to
  44.  * backup your work to a 'backup' disk.
  45.  *
  46.  *  backup [options] path path path ... path [-ooutputfile]
  47.  *
  48.  *    NOTE:    if -o is not specified, not output file will be created
  49.  *
  50.  *  options:
  51.  *
  52.  *    -A       ARCHIVE.  Clear the archive bit on backed up files
  53.  *
  54.  *    -U       UPDATE.     Backup only those files which have the archive bit
  55.  *           cleared.
  56.  *
  57.  *    -f[#KB]  Floppy... actually, this option is used to force the backup
  58.  *           program to automatically split up the backup files in #KB
  59.  *           sections (default 800).  I.E.  -f with nothing else will
  60.  *           use 800KB chunks.  -f200 would use 200KB chunks, etc...
  61.  *
  62.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  63.  *           AND RESTORE
  64.  *
  65.  *    -Fvol    example: -FDF0: -FDF1:  This command specifies the ordering
  66.  *           and number of (floppy) drives to backup to.  This allows
  67.  *           one to change floppies in one drive while it is backing up
  68.  *           to another.  It automatically cycles through the drives but
  69.  *           you still must specify an initial output file (-ofile) to
  70.  *           determine the base name for the files.
  71.  *
  72.  *           This command also forces user prompting.
  73.  *
  74.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  75.  *           AND RESTORE
  76.  *
  77.  *    -b       backup    (default if executable name is 'backup')
  78.  *
  79.  *    -r       restore    (default if executable nam is 'restore')
  80.  *
  81.  *    -a       append to the destination file.
  82.  *
  83.  *    -c       Compress files during backup
  84.  *
  85.  *    -s       Only display directories as we go along.
  86.  *
  87.  *    -l/-t    (either option) Causes a RESTORE to only LIST the files,
  88.  *           not do an actual restore.
  89.  *
  90.  *    -T       (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
  91.  *           NO files are created.  It is assumed the files already
  92.  *           exist.  The timestamp and other fields are transfered
  93.  *           from the backup file to the already-restored files (useful
  94.  *           if the files were restored with a copy command that did
  95.  *           non copy the timestamps.  Even if the backup file is old,
  96.  *           you can recover most of your time data).
  97.  *
  98.  *    -S       Silent.    Don't display files or directories.
  99.  *
  100.  *    -nKB     Set buffer size to use, in KB.
  101.  *
  102.  *    -v       Verbose... Additionaly, display those files which will NOT
  103.  *           be backed up.
  104.  *
  105.  *    -pPAT    only file-paths matching this pattern are backed up.  You
  106.  *           may specify more than one '-p' option.
  107.  *
  108.  *    -dPAT    file-paths matching this pattern are NOT backed up.  you
  109.  *           may specify more than one '-d' option.
  110.  *
  111.  *    -ofile   Output File
  112.  *
  113.  * ---------------------------------------------------------------------
  114.  *
  115.  * destination file format:
  116.  *
  117.  *  HDR = <HDR><N.B><datestamp>             -Backup Date
  118.  *  VOL = <VOL><name_size.B><name>            -VOLUME base
  119.  *  DDS = <DDS><name_size.B><name>            -down-directory
  120.  *  END = <END><0.B>                    -up directory
  121.  *  DAT = <DAT><N.B><datestamp>             -datestamp for file
  122.  *  PRO = <PRO><4.B><protection>            -protection for file
  123.  *  COM = <COM><N.B><comment>                -comment for file
  124.  *  FIL0= <FIL0><N.B><name><size.L><data>        -uncompressed file
  125.  *  FIL1= <FIL1><N.B><name><size.L><usize.L><data>  -compressed form #1
  126.  *  INC = <INC><12.B><ttlsize><strt><segsize>        -next file is part of an
  127.  *                             incomplete file
  128.  */
  129.  
  130. #include <stdio.h>
  131. #include <fcntl.h>
  132. #include <local/typedefs.h>
  133.  
  134. #define SDIR    struct _SDIR
  135. #define SCOMP    struct _SCOMP
  136.  
  137. SCOMP {
  138.     MNODE   Node;
  139.     uword   Bytes;    /*  allocated bytes            */
  140.     uword   N;
  141. };
  142.  
  143. SDIR {
  144.     MNODE   Node;    /*  node in dir tree            */
  145.     ubyte   Type;    /*  XDDS or XVOL            */
  146.     ubyte   HaveFile;    /*  Something was backed up in here */
  147.     char    *Element;    /*  path element            */
  148. };
  149.  
  150. #define XVOL    0x01
  151. #define XDDS    0x02
  152. #define XEND    0x03
  153. #define XDAT    0x04
  154. #define XPRO    0x05
  155. #define XCOM    0x06
  156. #define XFIL0    0x87
  157. #define XFIL1    0x88
  158. #define XHDR    0x09
  159. #define XINC    0x0A
  160.  
  161. ubyte    Break;
  162. ubyte    Restore;
  163. ubyte    ListOnly;
  164. ubyte    ShowFiles = 1;
  165. ubyte    ShowDirs  = 1;
  166. ubyte    Verbose;
  167. ubyte    Archive;
  168. ubyte    Update;
  169. ubyte    Append;
  170. ubyte    Compress;
  171. ubyte    TimeStampOnly;
  172. char    *OutFile;
  173. long    BacBytes;
  174. short    BacCnt = 1;
  175.  
  176. uword    NumPicks;
  177. uword    NumDels;
  178. char    *Picks[32];
  179. char    *Dels[32];
  180.  
  181. char DirPath[256];
  182. short DPLen;
  183.  
  184. long    BufSize = 65536;
  185. long    BufI;
  186. ubyte    *Buf;
  187. long    InBufSize = 8192;
  188. long    InBufI, InBufN;
  189. ubyte    *InBuf;
  190.  
  191. MLIST    VList;        /*    Volume list (-F), of NODEs              */
  192. MLIST    DList;        /*    Directory Stack             */
  193. long    CLen;        /*    Actual compressed file output length    */
  194. MLIST    CList;        /*    List of memory buffers            */
  195. SCOMP    *CWrite;    /*    Current memory buffer pointer        */
  196.  
  197. extern int Enable_Abort;
  198. extern void seekinputend();
  199. extern FIB *GetFileInfo();
  200. extern SCOMP *NewSComp();
  201. extern void *malloc(), *GetHead(), *GetTail(), *GetSucc(), *GetPred();
  202.  
  203. main(ac, av)
  204. char *av[];
  205. {
  206.     register short i, notdone;
  207.     register char  *str;
  208.  
  209.     NewList(&VList);
  210.     NewList(&DList);
  211.     NewList(&CList);
  212.  
  213.     Enable_Abort = 0;
  214.  
  215.  
  216.     for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
  217.     ++str;
  218.     if ((*str|0x20) == 'r')
  219.     Restore = 1;
  220.  
  221.     if (ac == 1) {
  222.     printf("Backup/Restore V2.01, (c)Copyright 1988 Matthew Dillon, All Rights Reserved\n", str);
  223.     printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile\n", str);
  224.     }
  225.  
  226.     for (i = 1; i < ac; ++i) {
  227.     str = av[i];
  228.     if (*str != '-')
  229.         continue;
  230.     notdone = 1;
  231.     ++str;
  232.     while (notdone && *str) {
  233.         switch(*str) {
  234.         case 'r':
  235.         Restore = 1;
  236.         break;
  237.         case 'b':
  238.         Restore = 0;
  239.         break;
  240.         case 'a':
  241.         Append = 1;
  242.         break;
  243.         case 'c':
  244.         Compress = 1;
  245.         break;
  246.         case 'd':
  247.         Dels[NumDels++] = str + 1;
  248.         notdone = 0;
  249.         break;
  250.         case 'f':
  251.         BacBytes = 800 * 1024;
  252.         if (str[1] >= '0' && str[1] <= '9') {
  253.             BacBytes = atoi(str+1) * 1024;
  254.             notdone = 0;
  255.         }
  256.         break;
  257.         case 'F':
  258.         {                    /*    strlen(str+1)+1 */
  259.             register NODE *node = malloc(sizeof(NODE)+strlen(str));
  260.             node->ln_Name = (char *)(node+1);
  261.             strcpy(node+1, str+1);
  262.             AddTail(&VList, node);
  263.         }
  264.         notdone = 0;
  265.         break;
  266.         case 'n':
  267.         BufSize = atoi(str+1) * 1024;
  268.         if (BufSize <= 0)
  269.             BufSize = 65536;
  270.         notdone = 0;
  271.         break;
  272.         case 'o':
  273.         OutFile = str + 1;
  274.         notdone = 0;
  275.         break;
  276.         case 'p':
  277.         Picks[NumPicks++] = str + 1;
  278.         notdone = 0;
  279.         break;
  280.         case 's':
  281.         ShowFiles = 0;
  282.         break;
  283.         case 't':
  284.         case 'l':
  285.         ListOnly = 1;
  286.         break;
  287.         case 'v':
  288.         Verbose= 1;
  289.         break;
  290.         case 'A':
  291.         Archive= 1;
  292.         break;
  293.         case 'S':
  294.         ShowFiles = 0;
  295.         ShowDirs  = 0;
  296.         break;
  297.         case 'T':
  298.         TimeStampOnly = 1;
  299.         break;
  300.         case 'U':
  301.         Update = 1;
  302.         break;
  303.         default:
  304.         puts("failure");
  305.         exit(20);
  306.         }
  307.         ++str;
  308.     }
  309.     }
  310.     Buf = malloc(BufSize);
  311.     if (Buf == NULL) {
  312.     printf("Unable to malloc %ld bytes\n", BufSize);
  313.     exit(20);
  314.     }
  315.     if (ListOnly)
  316.     InBufSize = 512;    /*  small buffer to avoid read overhead */
  317.                 /*  since we are skipping the meat    */
  318.  
  319.     InBuf = malloc(InBufSize);
  320.     if (InBuf == NULL) {
  321.     printf("Unable to malloc %ld bytes\n", InBufSize);
  322.     exit(20);
  323.     }
  324.  
  325.     if (Restore)
  326.     RestoreFiles(ac,av);
  327.     else
  328.     BackupFiles(ac,av);
  329. }
  330.  
  331. long SaveLock;
  332.  
  333. BackupFiles(ac, av)
  334. char *av[];
  335. {
  336.     register short i;
  337.     register char *str, *ptr;
  338.     char notdone;
  339.  
  340.     if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
  341.     exit(20);
  342.     if (OutFile) {      /*  write header    */
  343.     DATESTAMP Date;
  344.     DateStamp(&Date);
  345.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  346.     }
  347.  
  348.     SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  349.  
  350.     for (i = 1; i < ac; ++i) {
  351.     str = av[i];
  352.     if (*str == '-')
  353.         continue;
  354.     /*
  355.      *  Push DDS entries for each name segment of the path
  356.      */
  357.  
  358.     notdone = 1;
  359.     while (notdone) {
  360.         for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
  361.         switch(*ptr) {
  362.         case '/':   /*  normal directory    */
  363.         *ptr = 0;
  364.         PushDir(str, XDDS);
  365.         str = ptr + 1;
  366.         *ptr = '/';
  367.         break;
  368.         case ':':   /*  volume              */
  369.         *ptr = 0;
  370.         PushDir(str, XVOL);
  371.         str = ptr + 1;
  372.         *ptr = ':';
  373.         break;
  374.         default:    /*  directory or file    */
  375.         {
  376.             char *path = av[i];
  377.             FIB *fib;
  378.             long lock;
  379.  
  380.             if (fib = GetFileInfo(path, &lock)) {
  381.             if (fib->fib_DirEntryType > 0) {
  382.                 if (str[0])
  383.                 PushDir(str, XDDS);
  384.                 lock = scan_directory(fib, lock);
  385.                 if (str[0])
  386.                 PopDirs(1);
  387.             } else {
  388.                 lock = scan_file(fib, lock);
  389.             }
  390.             FreeFileInfo(fib, lock);
  391.             } else {
  392.             printf("Unable to get info for %s\n", av[i]);
  393.             }
  394.         }
  395.         notdone = 0;
  396.         break;
  397.         }
  398.     }
  399.     PopDirs(-1);
  400.     }
  401.  
  402.     UnLock(CurrentDir(SaveLock));
  403.     if (OutFile)
  404.     closeoutput();
  405. }
  406.  
  407. DATESTAMP Date;
  408. char Comment[256];
  409. char Scr[256];
  410. long Protection;
  411. long IncSize;        /*  Size of entire file     */
  412. long IncSeek;        /*  Seek offset into file   */
  413. long IncLen;        /*  # bytes in this segment */
  414.  
  415. RestoreFiles(ac, av)
  416. char *av[];
  417. {
  418.     register short i;
  419.     register char *str;
  420.     char notdone;
  421.     char havedate;
  422.     char havepro;
  423.     char havecom;
  424.     char haveinc;
  425.     long bytes;
  426.     long actual;
  427.     long lock;
  428.  
  429.     SaveLock = CurrentDir(lock = DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  430.  
  431.     for (i = 1; i < ac; ++i) {
  432.     str = av[i];
  433.     if (*str == '-')
  434.         continue;
  435.     if (openinput(str) == 0) {
  436.         printf("Unable to open %s for input\n", str);
  437.         continue;
  438.     }
  439.     notdone = 1;
  440.     havedate = havepro = havecom = haveinc = 0;
  441.     while (notdone) {
  442.         short c = oreadchar();
  443.         short l = oreadchar();
  444.         switch(c) {
  445.         case -1:
  446.         notdone = 0;
  447.         break;
  448.         case XVOL:
  449.         oread(Scr, l);
  450.         Scr[l] = 0;
  451.         if (OutFile) {      /*  Restore to OutFile instead  */
  452.             register short j = strlen(OutFile);
  453.             strcpy(Scr, OutFile);
  454.             if (j && OutFile[j-1] == '/') {
  455.             c = XDDS;
  456.             Scr[j-1] = 0;
  457.             } else if (j && OutFile[j-1] == ':') {
  458.             c = XVOL;
  459.             Scr[j-1] = 0;
  460.             } else
  461.             c = XDDS;
  462.         }
  463.         PushDir(Scr, c);
  464.         if (ListOnly)
  465.             break;
  466.         lock = Lock(DirPath, SHARED_LOCK);  /*  DirPath incs ':'    */
  467.         if (lock == NULL && c == XDDS) {
  468.             if (lock = CreateDir(Scr))      /*  Scr excludes '/'    */
  469.             UnLock(lock);
  470.             lock = Lock(Scr, SHARED_LOCK);
  471.         }
  472.         {
  473.             SDIR *sd = GetTail(&DList);
  474.             sd->HaveFile = 1;            /*    don't remove dir    */
  475.         }
  476.         if (lock == NULL) {
  477.             printf("Unable to create directory %s\n", Scr);
  478.             notdone = 0;
  479.         } else {
  480.             UnLock(CurrentDir(lock));
  481.         }
  482.         break;
  483.         case XDDS:
  484.         oread(Scr, l);
  485.         Scr[l] = 0;
  486.         PushDir(Scr, XDDS);
  487.         if (ListOnly)
  488.             break;
  489.         lock = Lock(Scr, SHARED_LOCK);
  490.         if (lock == NULL) {
  491.             if (lock = CreateDir(Scr))
  492.             UnLock(lock);
  493.             lock = Lock(Scr, SHARED_LOCK);
  494.         } else {
  495.             SDIR *sd = GetTail(&DList);
  496.             sd->HaveFile = 1;            /*    don't remove dir    */
  497.         }
  498.         if (lock == NULL) {
  499.             printf("Unable to create directory %s\n", Scr);
  500.             notdone = 0;
  501.         } else {
  502.             UnLock(CurrentDir(lock));
  503.         }
  504.         break;
  505.         case XEND:
  506.         {
  507.             SDIR *sd = GetTail(&DList);
  508.             ubyte type;
  509.  
  510.             c = 1;
  511.             if (!sd)
  512.             break;
  513.             type = sd->Type;
  514.             strcpy(Scr, sd->Element);
  515.             c = PopDirs(1);
  516.             if (ListOnly)
  517.             break;
  518.             if (type == XVOL)   /*  no parent directory */
  519.             break;
  520.             lock = ParentDir(lock);
  521.             if (lock == NULL) {
  522.             puts("Unable to ParentDir!");
  523.             notdone = 0;
  524.             } else {
  525.             if (c == 0)
  526.                 DeleteFile(Scr);
  527.             UnLock(CurrentDir(lock));
  528.             }
  529.         }
  530.         break;
  531.         case XDAT:
  532.         if (l != sizeof(DATESTAMP)) {
  533.             puts("expected sizeof datestamp");
  534.             notdone = 0;
  535.             break;
  536.         }
  537.         oread(&Date, l);
  538.         havedate = 1;
  539.         break;
  540.         case XPRO:
  541.         if (l != 4) {
  542.             puts("Expected 4 bytes for protection");
  543.             notdone = 0;
  544.             break;
  545.         }
  546.         oread(&Protection, l);
  547.         havepro = 1;
  548.         break;
  549.         case XCOM:
  550.         oread(Comment, l);
  551.         Comment[l] = 0;
  552.         havecom = 1;
  553.         break;
  554.         case XFIL0:
  555.         case XFIL1:
  556.         if (!havepro)
  557.             Protection = 0;
  558.         if (!havecom)
  559.             Comment[0] = 0;
  560.         if (!havedate)
  561.             DateStamp(&Date);
  562.         if (!haveinc)
  563.             IncSize = 0;
  564.  
  565.         oread(Scr, l);
  566.         Scr[l] = 0;
  567.         oread(&bytes, 4);       /*  length of file  */
  568.         actual = bytes;
  569.         if (c == XFIL1) {
  570.             oread(&actual, 4);
  571.             bytes -= 4;
  572.         }
  573.         setinputbound(bytes);
  574.         {
  575.             short res = read_file(c, Scr, bytes, actual);
  576.             seekinputend();
  577.             if (res < 0)
  578.             goto bend;
  579.         }
  580.         if (ListOnly)
  581.             goto bend;
  582.         if (Archive)
  583.             SetProtection(Scr, Protection|FIBF_ARCHIVE);
  584.         else
  585.             SetProtection(Scr, Protection&~FIBF_ARCHIVE);
  586.         if (havedate)
  587.             setfiledate(Scr, &Date);
  588.         if (havecom && Comment[0])
  589.             SetComment(Scr, Comment);
  590. bend:
  591.         havecom = havedate = havepro = haveinc = 0;
  592.         break;
  593.         case XHDR:
  594.         if (l != sizeof(DATESTAMP)) {
  595.             puts("expected sizeof datestamp");
  596.             notdone = 0;
  597.             break;
  598.         }
  599.         oread(&Date, l);
  600.         printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
  601.         break;
  602.         case XINC:
  603.         if (l != 12) {
  604.             puts("expected 12 bytes for XINC");
  605.             notdone = 0;
  606.             break;
  607.         }
  608.         oread(&IncSize, 4);
  609.         oread(&IncSeek, 4);
  610.         oread(&IncLen,  4);
  611.         haveinc = 1;
  612.         break;
  613.         default:
  614.         printf("Unknown Record Type: %02x\n", c);
  615.         notdone = 0;
  616.         break;
  617.         }
  618.         setinputbound(-1);
  619.         if (mycheckbreak()) {
  620.         Break = 1;
  621.         notdone = 0;
  622.         break;
  623.         }
  624.     }
  625.     if (Break)
  626.         break;
  627.     }
  628.     UnLock(CurrentDir(SaveLock));
  629. }
  630.  
  631. FIB *
  632. GetFileInfo(path, plock)
  633. char *path;
  634. long *plock;
  635. {
  636.     register long lock;
  637.     register FIB *fib;
  638.  
  639.     *plock = NULL;
  640.     if (lock = Lock(path, SHARED_LOCK)) {
  641.     if (fib = malloc(sizeof(FIB))) {
  642.         if (Examine(lock, fib)) {
  643.         *plock = lock;
  644.         return(fib);
  645.         }
  646.         free(fib);
  647.     }
  648.     UnLock(lock);
  649.     }
  650.     return(NULL);
  651. }
  652.  
  653. FreeFileInfo(fib, lock)
  654. FIB *fib;
  655. long lock;
  656. {
  657.     if (fib)
  658.     free(fib);
  659.     if (lock)
  660.     UnLock(lock);
  661. }
  662.  
  663.  
  664. PushDir(element, type)
  665. char *element;
  666. {
  667.     register SDIR *sd = malloc(sizeof(SDIR));
  668.     register char *str = malloc(strlen(element)+1);
  669.  
  670.     strcpy(str, element);
  671.     sd->Type = type;
  672.     sd->HaveFile = 0;
  673.     sd->Element = str;
  674.     AddTail(&DList, sd);
  675.     strcat(DirPath+DPLen, str);
  676.     if (type == XVOL)
  677.     strcat(DirPath+DPLen, ":");
  678.     else
  679.     strcat(DirPath+DPLen, "/");
  680.     DPLen += strlen(DirPath+DPLen);
  681. }
  682.  
  683. PopDirs(num)
  684. uword num;
  685. {
  686.     register SDIR *sd, *sp;
  687.     char lasthave = 0;
  688.  
  689.     while (num && (sd = GetTail(&DList))) {
  690.     lasthave |= sd->HaveFile;
  691.     if (sd->HaveFile)       /*  MUST write end-block    */
  692.         outentry(XEND, 0, NULL);
  693.     if (sp = GetPred(sd))
  694.         sp->HaveFile |= sd->HaveFile;
  695.     Remove(sd);
  696.     DPLen -= strlen(sd->Element) + 1;
  697.     if (DPLen < 0) {
  698.         puts("DPLEN ERROR");
  699.         DPLen = 0;
  700.     }
  701.     DirPath[DPLen] = 0;
  702.     free(sd->Element);
  703.     free(sd);
  704.     --num;
  705.     }
  706.     return(lasthave);
  707. }
  708.  
  709. /*
  710.  *  SCAN_DIRECTORY()        (CORE OF BACKUP)
  711.  */
  712.  
  713. scan_directory(dirfib, dirlock)
  714. FIB *dirfib;
  715. long dirlock;
  716. {
  717.     register FIB *fib;
  718.     long lock;
  719.     long save = CurrentDir(dirlock);
  720.  
  721.     while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
  722.     if (fib->fib_DirEntryType > 0) {
  723.         PushDir(fib->fib_FileName, XDDS);
  724.         if (ShowDirs)
  725.         printf("%-40s (DIR)\n", DirPath);
  726.         lock = scan_directory(fib, lock);
  727.         PopDirs(1);
  728.     } else {
  729.         lock = scan_file(fib, lock);
  730.     }
  731.     FreeFileInfo(fib, lock);
  732.     if (Break || mycheckbreak()) {
  733.         Break = 1;
  734.         break;
  735.     }
  736.     }
  737.     CurrentDir(save);
  738.     return(dirlock);
  739. }
  740.  
  741. mycheckbreak()
  742. {
  743.     if (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  744.     puts(" ***** BREAK *****");
  745.     return(1);
  746.     }
  747.     return(0);
  748. }
  749.  
  750. /*
  751.  *  SCAN_FILE()
  752.  *
  753.  *  If the file is accepted, write out pending directory entries, do
  754.  *  compression if any, and write out the file.
  755.  */
  756.  
  757. scan_file(fib, lock)
  758. FIB *fib;
  759. long lock;
  760. {
  761.     long save;
  762.     long n;
  763.     char dbuf[32];
  764.  
  765.     strcat(DirPath, fib->fib_FileName);
  766.  
  767.     if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
  768.     goto nomatch;
  769.     {
  770.     register short i;
  771.  
  772.     for (i = 0; i < NumPicks; ++i) {
  773.         if (wildcmp(Picks[i], DirPath))
  774.         break;
  775.     }
  776.     if (i && i == NumPicks)
  777.         goto nomatch;
  778.  
  779.     for (i = 0; i < NumDels; ++i) {
  780.         if (wildcmp(Dels[i], DirPath))
  781.         goto nomatch;
  782.     }
  783.     }
  784.  
  785.     if (ShowFiles)
  786.     printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  787.  
  788.     {
  789.     register SDIR *sd;
  790.     SDIR *sdb = NULL;
  791.  
  792.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  793.         if (sd->HaveFile == 0)
  794.         sdb = sd;
  795.     }
  796.     for (sd = sdb; sd; sd = GetSucc(sd)) {
  797.         sd->HaveFile = 1;
  798.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  799.     }
  800.     }
  801.     if (OutFile) {
  802.     save = CurrentDir(lock);
  803.     if (openinput("") == 0) {
  804.         CurrentDir(save);
  805.         printf("Unable to open %s\n", fib->fib_FileName);
  806.         goto nomatch;
  807.     }
  808.     if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
  809.         if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
  810.         if (newfile() == 0)
  811.             goto skip1;
  812.         }
  813.         writeheaders(fib);
  814.         outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
  815.         CLen += 4;
  816.         owrite(&CLen, 4);
  817.         CLen -= 4;
  818.         owrite(&fib->fib_Size, 4);
  819.         transfer1(fib->fib_Size);
  820.     } else {
  821.         if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
  822.         if (newfile() == 0)
  823.             goto skip1;
  824.         }
  825.         if (Compress)
  826.         rollbackinput();
  827.         writeheaders(fib);
  828.         outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
  829.         owrite(&fib->fib_Size, 4);
  830.         transfer0(fib->fib_Size);
  831.     }
  832. skip1:
  833.     closeinput();
  834.     CurrentDir(save);
  835.     }
  836.     if (Break)
  837.     goto nomatch;
  838.     if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
  839.     if (save = ParentDir(lock)) {
  840.         UnLock(lock);
  841.         save = CurrentDir(save);
  842.         SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
  843.         lock = CurrentDir(save);
  844.     }
  845.     }
  846.     DirPath[DPLen] = 0;
  847.     return(lock);
  848. nomatch:
  849.     if (Verbose)
  850.     printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  851.  
  852.     DirPath[DPLen] = 0;
  853.     return(lock);
  854. }
  855.  
  856. writeheaders(fib)
  857. register FIB *fib;
  858. {
  859.     outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
  860.     outentry(XPRO, 4, &fib->fib_Protection);
  861.     if (fib->fib_Comment[0])
  862.     outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
  863. }
  864.  
  865. /*
  866.  *  (1) Write out XEND's to finish this archive,
  867.  *  (2) Open a new output file
  868.  *  (3) Write out XDDS's to build back to the current position
  869.  */
  870.  
  871. newfile()
  872. {
  873.     {
  874.     register SDIR *sd;
  875.  
  876.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  877.         if (sd->HaveFile)
  878.         outentry(XEND, 0, NULL);
  879.     }
  880.     }
  881.     ++BacCnt;
  882.     if (OutFile && openoutput(OutFile, Append, 1) == 0) {
  883.     Break = 1;
  884.     return(0);
  885.     }
  886.     {
  887.     register SDIR *sd;
  888.     DATESTAMP Date;
  889.     DateStamp(&Date);
  890.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  891.     for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
  892.         if (sd->HaveFile)
  893.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  894.     }
  895.     }
  896.     return(1);
  897. }
  898.  
  899. read_file(type, fname, inbytes, outbytes)
  900. short type;
  901. char *fname;
  902. {
  903.     char dbuf[32];
  904.  
  905.     strcat(DirPath, fname);
  906.     {
  907.     register short i;
  908.  
  909.     for (i = 0; i < NumPicks; ++i) {
  910.         if (wildcmp(Picks[i], DirPath))
  911.         break;
  912.     }
  913.     if (i && i == NumPicks) {
  914.         if (Verbose)
  915.         printf("%-40s (NOT ACCEPTED)\n", DirPath);
  916.         goto nomatch;
  917.     }
  918.  
  919.     for (i = 0; i < NumDels; ++i) {
  920.         if (wildcmp(Dels[i], DirPath)) {
  921.         if (Verbose)
  922.             printf("%-40s (NOT ACCEPTED)\n", DirPath);
  923.         goto nomatch;
  924.         }
  925.     }
  926.     }
  927.  
  928.     printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
  929.  
  930.     if (ListOnly)
  931.     goto nomatch;
  932.     if (TimeStampOnly)
  933.     goto matchskip;
  934.  
  935.     openoutput(fname, 0, 0);
  936.     switch(type) {
  937.     case XFIL0:
  938.     transfer0(inbytes);
  939.     break;
  940.     case XFIL1:
  941.     UnCompressFile(inbytes);
  942.     transfer1(outbytes);
  943.     break;
  944.     }
  945.     closeoutput();
  946. matchskip:
  947.     DirPath[DPLen] = 0;
  948.     return(1);
  949. nomatch:
  950.     DirPath[DPLen] = 0;
  951.     return(-1);
  952. }
  953.  
  954. /*
  955.  *  FILE SUPPORT
  956.  */
  957.  
  958. static int Infd = -1;
  959. static int Outfd = -1;
  960. static long OutBytes;
  961.  
  962. openoutput(name, append, enabtail)
  963. char *name;
  964. {
  965.     char *ptr = name;
  966.     static NODE *VNode;     /*    Volume node */
  967.     long lock;
  968.     extern int errno;
  969.  
  970.     if (Outfd >= 0) {
  971.     dumpoutput();
  972.     close(Outfd);
  973.     Outfd = -1;
  974.     }
  975.     if (enabtail) {
  976.     if (VNode)
  977.         VNode = GetSucc(VNode);
  978.     if (!VNode)
  979.         VNode = GetHead(&VList);
  980.     if (VNode) {
  981.         ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
  982.         sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
  983.     } else {
  984.         ptr = malloc(strlen(name)+8);
  985.         sprintf(ptr, "%s.%02ld", name, BacCnt);
  986.     }
  987.     }
  988.     OutBytes = 0;
  989.     while (GetHead(&VList)) {
  990.     short c;
  991.     short d;
  992.  
  993.     fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
  994.     fflush(stderr);
  995.     if ((c = getc(stdin)) == EOF) {
  996.         fprintf(stderr, "EOF, aborted\n");
  997.         c = 'n';
  998.     }
  999.     while ((d = getc(stdin)) != EOF && d != '\n');
  1000.     if ((c|0x20) == 'y')
  1001.         break;
  1002.     if ((c|0x20) == 'n')
  1003.         goto skip;
  1004.     }
  1005.     if (enabtail && SaveLock)                 /*  original directory  */
  1006.     lock = CurrentDir(SaveLock);
  1007.     if (append) {
  1008.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
  1009.     if (Outfd >= 0) {
  1010.         OutBytes = lseek(Outfd, 0L, 2);
  1011.         if (!append)
  1012.         lseek(Outfd, 0L, 0);
  1013.     }
  1014.     } else {
  1015.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
  1016.     }
  1017.     if (enabtail && SaveLock)                 /*  back to before      */
  1018.     CurrentDir(lock);
  1019.     if (Outfd < 0)
  1020.     printf("Unable to open output file %s (%ld)\n", ptr, errno);
  1021. skip:
  1022.     BufI = 0;
  1023.     if (enabtail)
  1024.     free(ptr);
  1025.     return(Outfd >= 0);
  1026. }
  1027.  
  1028. oputc(v)
  1029. char v;
  1030. {
  1031.     ++OutBytes;
  1032.     if (Outfd >= 0) {
  1033.     if (BufI == BufSize)
  1034.         dumpoutput();
  1035.     Buf[BufI++] = v;
  1036.     }
  1037. }
  1038.  
  1039. owrite(buf, n)
  1040. register char *buf;
  1041. register long n;
  1042. {
  1043.     register long avail;
  1044.  
  1045.     OutBytes += n;
  1046.     if (Outfd >= 0) {
  1047.     while (BufI + n > BufSize) {
  1048.         avail = BufSize - BufI;
  1049.         bmov(buf, Buf + BufI, avail);
  1050.         n  -= avail;
  1051.         buf+= avail;
  1052.         BufI = BufSize;
  1053.         dumpoutput();
  1054.     }
  1055.     bmov(buf, Buf + BufI, n);
  1056.     BufI += n;
  1057.     }
  1058. }
  1059.  
  1060. dumpoutput()
  1061. {
  1062.     if (Outfd >= 0 && BufI) {
  1063.     write(Outfd, Buf, BufI);
  1064.     BufI = 0;
  1065.     }
  1066. }
  1067.  
  1068. closeoutput()
  1069. {
  1070.     if (Outfd >= 0) {
  1071.     dumpoutput();
  1072.     close(Outfd);
  1073.     Outfd = -1;
  1074.     }
  1075. }
  1076.  
  1077. outbytes()
  1078. {
  1079.     return(OutBytes);
  1080. }
  1081.  
  1082. /*
  1083.  *  <type><len><buf>
  1084.  */
  1085.  
  1086. outentry(type, len, buf)
  1087. ubyte type;
  1088. ubyte len;
  1089. ubyte *buf;
  1090. {
  1091.     OutBytes += len + 2;
  1092.     if (Outfd >= 0) {
  1093.     if (BufI + len + 2 >= BufSize)
  1094.         dumpoutput();
  1095.     Buf[BufI+0] = type;
  1096.     Buf[BufI+1] = len;
  1097.     bmov(buf, Buf+BufI+2, len);
  1098.     BufI += len + 2;
  1099.     }
  1100. }
  1101.  
  1102. ulong OMax;
  1103.  
  1104. openinput(name)
  1105. char *name;
  1106. {
  1107.     if (Infd >= 0)
  1108.     close(Infd);
  1109.     Infd = open(name, O_RDONLY);
  1110.     InBufI = InBufN = 0;
  1111.     OMax = -1;
  1112.     return(Infd >= 0);
  1113. }
  1114.  
  1115. closeinput()
  1116. {
  1117.     if (Infd >= 0)
  1118.     close(Infd);
  1119.     Infd = -1;
  1120. }
  1121.  
  1122. void
  1123. seekinputend()
  1124. {
  1125.     register long inbuf   = InBufI - InBufN;
  1126.     register long forward = OMax;
  1127.  
  1128.     if (forward > inbuf) {
  1129.     lseek(Infd, forward - inbuf, 1);
  1130.     OMax = InBufI = InBufN = 0;
  1131.     return;
  1132.     }
  1133.     InBufN += forward;
  1134. }
  1135.  
  1136. setinputbound(max)
  1137. {
  1138.     OMax = max;
  1139. }
  1140.  
  1141. oread(buf, n)
  1142. char *buf;
  1143. long n;
  1144. {
  1145.     long x = 0;
  1146.     long avail;
  1147.  
  1148.     if (Infd < 0)
  1149.     return(0);
  1150.     if (n > OMax)
  1151.     n = OMax;
  1152.  
  1153.     while (n > (avail = InBufI - InBufN)) {
  1154.     if (InBufN == -1)
  1155.         return(0);
  1156.     bmov(InBuf + InBufN, buf, avail);
  1157.     OMax-= avail;
  1158.     n   -= avail;
  1159.     buf += avail;
  1160.     x   += avail;
  1161.     InBufI = read(Infd, InBuf, InBufSize);
  1162.     InBufN = 0;
  1163.     if (InBufI <= 0) {
  1164.         InBufI = 0;
  1165.         return(x);
  1166.     }
  1167.     }
  1168.     bmov(InBuf + InBufN, buf, n);
  1169.     InBufN += n;
  1170.     x += n;
  1171.     OMax -= n;
  1172.     return(x);
  1173. }
  1174.  
  1175. oreadchar()
  1176. {
  1177.     if (!OMax || Infd < 0)
  1178.     return(-1);
  1179.     if (InBufN == InBufI) {
  1180.     if (InBufN < 0)
  1181.         return(EOF);
  1182.     InBufI = read(Infd, InBuf, InBufSize);
  1183.     InBufN = 0;
  1184.     if (InBufI == 0) {
  1185.         InBufN = InBufI = -1;
  1186.         return(-1);
  1187.     }
  1188.     }
  1189.     return(InBuf[InBufN++]);
  1190. }
  1191.  
  1192. rollbackinput()
  1193. {
  1194.     if (Infd >= 0)
  1195.     lseek(Infd, 0L, 0);
  1196.     InBufI = InBufN = 0;
  1197. }
  1198.  
  1199. mputc(v)
  1200. char v;
  1201. {
  1202.     register SCOMP *sc = CWrite;
  1203.  
  1204.     ++CLen;
  1205.     if (sc->N == sc->Bytes) {
  1206.     sc = GetSucc(sc);
  1207.     if (sc == NULL);
  1208.         sc = NewSComp();
  1209.     if (sc == NULL) {
  1210.         puts("SCOMP FAILED");
  1211.         return(0);
  1212.     }
  1213.     sc->N = 0;
  1214.     CWrite = sc;
  1215.     }
  1216.     ((char *)(sc + 1))[sc->N++] = v;
  1217. }
  1218.  
  1219. mwrite(buf, n)
  1220. char *buf;
  1221. long n;
  1222. {
  1223.     register SCOMP *sc = CWrite;
  1224.     register long avail;
  1225.  
  1226.     CLen += n;
  1227.     while ((avail = sc->Bytes - sc->N) < n) {
  1228.     bmov(buf, (char *)(sc + 1) + sc->N, avail);
  1229.     buf += avail;
  1230.     n -= avail;
  1231.     sc->N = sc->Bytes;
  1232.     sc = GetSucc(sc);
  1233.     if (sc == NULL)
  1234.         sc = NewSComp();
  1235.     if (sc == NULL) {
  1236.         puts("SCOMP FAILED");
  1237.         return(0);
  1238.     }
  1239.     sc->N = 0;
  1240.     }
  1241.     bmov(buf, (char *)(sc + 1) + sc->N, n);
  1242.     sc->N += n;
  1243.     CWrite = sc;
  1244. }
  1245.  
  1246. SCOMP *
  1247. NewSComp()
  1248. {
  1249.     register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
  1250.  
  1251.     if (sc) {
  1252.     sc->Bytes = 8192;
  1253.     sc->N = 0;
  1254.     AddTail(&CList, sc);
  1255.     }
  1256.     return(sc);
  1257. }
  1258.  
  1259. transfer0(n)
  1260. long n;
  1261. {
  1262.     register long len;
  1263.  
  1264.     if (Outfd < 0)
  1265.     return(n);
  1266.     for (len = BufSize - BufI; n; len = BufSize - BufI) {
  1267.     if (len == 0) {
  1268.         dumpoutput();
  1269.         len = BufSize;
  1270.     }
  1271.     if (n < len)
  1272.         len = n;
  1273.     oread(Buf + BufI, len);
  1274.     BufI += len;
  1275.     n -= len;
  1276.     OutBytes += len;
  1277.     }
  1278. }
  1279.  
  1280. /*
  1281.  *  Compression Routines
  1282.  *
  1283.  *  transfer1(n)    : Backup:   copy compression buffer to output file
  1284.  */
  1285.  
  1286. transfer1(a)
  1287. {
  1288.     register long len;
  1289.     register SCOMP *sc = GetHead(&CList);
  1290.     register ubyte *ptr;
  1291.     long n = CLen;
  1292.  
  1293.     if (Outfd < 0)
  1294.     return(n);
  1295.     for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
  1296.     len = sc->Bytes;
  1297.     ptr = (ubyte *)(sc + 1);
  1298.     if (n < len)
  1299.         len = n;
  1300.     n -= len;
  1301.     while (len > BufSize - BufI) {
  1302.         bmov(ptr, Buf + BufI, BufSize - BufI);
  1303.         ptr += BufSize - BufI;
  1304.         len -= BufSize - BufI;
  1305.         OutBytes += BufSize - BufI;
  1306.         BufI = BufSize;
  1307.         dumpoutput();
  1308.     }
  1309.     bmov(ptr, Buf + BufI, len);
  1310.     BufI += len;
  1311.     OutBytes += len;
  1312.     }
  1313.     if (n)
  1314.     puts("Unexpected EOF in compression file");
  1315. }
  1316.  
  1317. #asm
  1318.  
  1319.         ;    Taken from my DRES.LIBRARY so we don't have to open the
  1320.         ;    library.
  1321.  
  1322.         public  _GetHead
  1323.         public  _GetTail
  1324.         public  _GetSucc
  1325.         public  _GetPred
  1326.  
  1327. _GetSucc:
  1328. _GetHead:   move.l  4(sp),A0
  1329.         move.l  (A0),A0
  1330.         tst.l   (A0)
  1331.         bne     .gh1
  1332. .ghz        sub.l   A0,A0
  1333. .gh1        move.l  A0,D0
  1334.         rts
  1335.  
  1336. _GetTail:   move.l  4(sp),A0
  1337.         move.l  8(A0),A0
  1338.         tst.l   4(A0)
  1339.         beq     .ghz
  1340.         move.l  A0,D0
  1341.         rts
  1342.  
  1343. _GetPred:   move.l  4(sp),A0
  1344.         move.l  4(A0),A0
  1345.         tst.l   4(A0)
  1346.         beq     .ghz
  1347.         move.l  A0,D0
  1348.         rts
  1349.  
  1350. #endasm
  1351.  
  1352. #define ngetchar()  oreadchar()
  1353. #define nputchar(n) mputc(n)
  1354.  
  1355. #ifndef min
  1356. #define min(a,b)        ((a>b) ? b : a)
  1357. #endif
  1358.  
  1359. #define BITS        13
  1360.  
  1361. #if BITS == 16
  1362. #define HSIZE  69001           /* 95% occupancy */
  1363. #endif
  1364. #if BITS == 15
  1365. #define HSIZE  35023           /* 94% occupancy */
  1366. #endif
  1367. #if BITS == 14
  1368. #define HSIZE  18013           /* 91% occupancy */
  1369. #endif
  1370. #if BITS == 13
  1371. #define HSIZE  9001           /* 91% occupancy */
  1372. #endif
  1373. #if BITS <= 12
  1374. #define HSIZE  5003           /* 80% occupancy */
  1375. #endif
  1376.  
  1377. typedef long        code_int;
  1378. typedef long        count_int;
  1379. typedef unsigned char    char_type;
  1380.  
  1381. #define MAXCODE(n_bits)  ((1 << (n_bits)) - 1)
  1382. #define INIT_BITS 9            /* initial number of bits/code */
  1383.  
  1384. int n_bits;                /* number of bits/code            */
  1385. int maxbits;                /* user settable max # bits/code    */
  1386. code_int maxcode;            /* maximum code, given n_bits        */
  1387. code_int maxmaxcode;            /* should NEVER generate this code  */
  1388.  
  1389. count_int   htab[HSIZE];
  1390. uword        codetab[HSIZE];
  1391.  
  1392. #define htabof(i)       htab[i]
  1393. #define codetabof(i)    codetab[i]
  1394.  
  1395. code_int hsize = HSIZE;         /* for dynamic table sizing */
  1396.  
  1397. #define tab_prefixof(i)     codetabof(i)
  1398. #define tab_suffixof(i)     ((char_type *)(htab))[i]
  1399. #define de_stack        ((char_type *)&tab_suffixof(1<<BITS))
  1400.  
  1401. code_int free_ent;            /* first unused entry */
  1402.  
  1403. code_int getcode();
  1404.  
  1405. #define CHECK_GAP 10000 /* ratio check interval */
  1406.  
  1407. int    block_compress = 1;
  1408. int    clear_flg;
  1409. long    ratio;
  1410. count_int checkpoint;
  1411.  
  1412. /*
  1413.  * the next two codes should not be changed lightly, as they must not
  1414.  * lie within the contiguous general code space.
  1415.  */
  1416.  
  1417. #define FIRST    257    /* first free entry */
  1418. #define CLEAR    256    /* table clear output code */
  1419.  
  1420. static int offset;
  1421. long int in_count = 1;            /* length of input */
  1422.  
  1423. /*
  1424.  *  Compress a file to memory-buffers and return TRUE if the compressed
  1425.  *  size is smaller than the actual size.
  1426.  */
  1427.  
  1428. CompressFile(name, fsize)
  1429. {
  1430.     long fcode;
  1431.     code_int i = 0;
  1432.     int c;
  1433.     code_int ent;
  1434.     int disp;
  1435.     code_int hsize_reg;
  1436.     int hshift;
  1437.  
  1438.     if (wildcmp("*.Z", name) || wildcmp("*.ARC", name) || wildcmp("*.ZOO", name)) {
  1439.     printf("  Will not compress %s\n", name);
  1440.     return(0);
  1441.     }
  1442.  
  1443.     CLen = 0;
  1444.     CWrite = GetHead(&CList);
  1445.     if (CWrite == NULL)
  1446.     CWrite = NewSComp();
  1447.     CWrite->N = 0;
  1448.  
  1449.     bzero(htab, sizeof(htab));
  1450.     bzero(codetab, sizeof(codetab));
  1451.  
  1452.     hsize = HSIZE;
  1453.     if ( fsize < (1 << 12) )
  1454.     hsize = min ( 5003, HSIZE );
  1455.     else if ( fsize < (1 << 13) )
  1456.     hsize = min ( 9001, HSIZE );
  1457.     else if ( fsize < (1 << 14) )
  1458.     hsize = min ( 18013, HSIZE );
  1459.     else if ( fsize < (1 << 15) )
  1460.     hsize = min ( 35023, HSIZE );
  1461.     else if ( fsize < 47000 )
  1462.     hsize = min ( 50021, HSIZE );
  1463.  
  1464.     offset = clear_flg = ratio = 0;
  1465.     in_count = 1;
  1466.     checkpoint = CHECK_GAP;
  1467.     n_bits  = INIT_BITS;        /* number of bits/code            */
  1468.     maxbits = BITS;            /* user settable max # bits/code    */
  1469.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  1470.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  1471.     free_ent = ((block_compress) ? FIRST : 256 );
  1472.  
  1473.     ent = ngetchar();
  1474.  
  1475.     hshift = 0;
  1476.     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
  1477.     hshift++;
  1478.     hshift = 8 - hshift;        /* set hash code range bound */
  1479.  
  1480.     hsize_reg = hsize;
  1481.     cl_hash((count_int)hsize_reg);      /* clear hash table */
  1482.  
  1483.     while ((c = ngetchar()) != EOF) {
  1484.     in_count++;
  1485.     fcode = (long) (((long) c << maxbits) + ent);
  1486.     i = ((c << hshift) ^ ent);      /* xor hashing */
  1487.  
  1488.     if (htabof (i) == fcode) {
  1489.         ent = codetabof(i);
  1490.         continue;
  1491.     } else if ((long)htabof (i) < 0)    /* empty slot */
  1492.         goto nomatch;
  1493.     disp = hsize_reg - i;        /* secondary hash (after G. Knott) */
  1494.     if (i == 0)
  1495.         disp = 1;
  1496. probe:
  1497.     if ((i -= disp) < 0)
  1498.         i += hsize_reg;
  1499.  
  1500.     if (htabof (i) == fcode) {
  1501.         ent = codetabof(i);
  1502.         continue;
  1503.     }
  1504.     if ((long)htabof (i) > 0)
  1505.         goto probe;
  1506. nomatch:
  1507.     output ((code_int) ent);
  1508.     ent = c;
  1509.     if (free_ent < maxmaxcode) {
  1510.         codetabof(i) = free_ent++; /* code -> hashtable */
  1511.         htabof(i) = fcode;
  1512.     }
  1513.     else if ((count_int)in_count >= checkpoint && block_compress)
  1514.         cl_block ();
  1515.     }
  1516.  
  1517.     /*
  1518.      * Put out the final code.
  1519.      */
  1520.  
  1521.     output((code_int)ent);
  1522.     output((code_int)-1);
  1523.  
  1524.     return(CLen < fsize);
  1525. }
  1526.  
  1527. static char buf[BITS];
  1528.  
  1529. char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
  1530. char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  1531.  
  1532. output( code )
  1533. code_int  code;
  1534. {
  1535.     register int r_off = offset, bits= n_bits;
  1536.     register char * bp = buf;
  1537.  
  1538.     if ( code >= 0 ) {
  1539.     /*
  1540.      * Get to the first byte.
  1541.      */
  1542.     bp += (r_off >> 3);
  1543.     r_off &= 7;
  1544.     /*
  1545.      * Since code is always >= 8 bits, only need to mask the first
  1546.      * hunk on the left.
  1547.      */
  1548.     *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
  1549.     bp++;
  1550.     bits -= (8 - r_off);
  1551.     code >>= 8 - r_off;
  1552.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  1553.     if ( bits >= 8 ) {
  1554.         *bp++ = code;
  1555.         code >>= 8;
  1556.         bits -= 8;
  1557.     }
  1558.     /* Last bits. */
  1559.     if(bits)
  1560.         *bp = code;
  1561.  
  1562.     offset += n_bits;
  1563.     if (offset == (n_bits << 3)) {
  1564.         bp = buf;
  1565.         bits = n_bits;
  1566.         mwrite(bp, bits);
  1567.         bp += bits;
  1568.         bits = 0;
  1569.         offset = 0;
  1570.     }
  1571.  
  1572.     /*
  1573.      * If the next entry is going to be too big for the code size,
  1574.      * then increase it, if possible.
  1575.      */
  1576.  
  1577.     if (free_ent > maxcode || (clear_flg > 0)) {
  1578.         /*
  1579.          * Write the whole buffer, because the input side won't
  1580.          * discover the size increase until after it has read it.
  1581.          */
  1582.         if (offset > 0)
  1583.         mwrite(buf, n_bits);
  1584.         offset = 0;
  1585.  
  1586.         if (clear_flg) {
  1587.         n_bits = INIT_BITS;
  1588.         maxcode = MAXCODE(INIT_BITS);
  1589.         clear_flg = 0;
  1590.         } else {
  1591.         n_bits++;
  1592.         if (n_bits == maxbits)
  1593.             maxcode = maxmaxcode;
  1594.         else
  1595.             maxcode = MAXCODE(n_bits);
  1596.         }
  1597.     }
  1598.     } else {
  1599.     /*
  1600.      * At EOF, write the rest of the buffer.
  1601.      */
  1602.     if (offset > 0)
  1603.         mwrite(buf, (offset + 7) / 8);
  1604.     offset = 0;
  1605.     }
  1606. }
  1607.  
  1608.  
  1609. char *
  1610. xrindex(s, c)            /* For those who don't have it in libc.a */
  1611. register char *s, c;
  1612. {
  1613.     char *p;
  1614.     for (p = NULL; *s; s++) {
  1615.     if (*s == c)
  1616.         p = s;
  1617.     }
  1618.     return(p);
  1619. }
  1620.  
  1621.  
  1622. cl_block()             /* table clear for block compress */
  1623. {
  1624.     register long int rat;
  1625.  
  1626.     checkpoint = in_count + CHECK_GAP;
  1627.  
  1628.     if (in_count > 0x007fffff) { /* shift will overflow */
  1629.     rat = CLen >> 8;
  1630.     if (rat == 0) {          /* Don't divide by zero */
  1631.         rat = 0x7fffffff;
  1632.     } else {
  1633.         rat = in_count / rat;
  1634.     }
  1635.     } else {
  1636.     rat = (in_count << 8) / CLen;      /* 8 fractional bits */
  1637.     }
  1638.     if (rat > ratio) {
  1639.     ratio = rat;
  1640.     } else {
  1641.     ratio = 0;
  1642.     cl_hash ( (count_int) hsize );
  1643.     free_ent = FIRST;
  1644.     clear_flg = 1;
  1645.     output ( (code_int) CLEAR );
  1646.     }
  1647. }
  1648.  
  1649. cl_hash(hsize)          /* reset code table */
  1650.     register count_int hsize;
  1651. {
  1652.     register count_int *htab_p = htab+hsize;
  1653.     register long i;
  1654.     register long m1 = -1;
  1655.  
  1656.     i = hsize - 16;
  1657.     do {                /* might use Sys V memset(3) here */
  1658.         *(htab_p-16) = m1;
  1659.         *(htab_p-15) = m1;
  1660.         *(htab_p-14) = m1;
  1661.         *(htab_p-13) = m1;
  1662.         *(htab_p-12) = m1;
  1663.         *(htab_p-11) = m1;
  1664.         *(htab_p-10) = m1;
  1665.         *(htab_p-9) = m1;
  1666.         *(htab_p-8) = m1;
  1667.         *(htab_p-7) = m1;
  1668.         *(htab_p-6) = m1;
  1669.         *(htab_p-5) = m1;
  1670.         *(htab_p-4) = m1;
  1671.         *(htab_p-3) = m1;
  1672.         *(htab_p-2) = m1;
  1673.         *(htab_p-1) = m1;
  1674.         htab_p -= 16;
  1675.     } while ((i -= 16) >= 0);
  1676.     for ( i += 16; i > 0; i-- )
  1677.         *--htab_p = m1;
  1678. }
  1679.  
  1680. UnCompressFile(insize)
  1681. {
  1682.     register char_type *stackp;
  1683.     register int finchar;
  1684.     register code_int code, oldcode, incode;
  1685.  
  1686.     /*
  1687.      * As above, initialize the first 256 entries in the table.
  1688.      */
  1689.  
  1690.     bzero(htab, sizeof(htab));
  1691.     bzero(codetab, sizeof(codetab));
  1692.  
  1693.     offset = clear_flg = ratio = 0;
  1694.     in_count = 1;
  1695.     checkpoint = CHECK_GAP;
  1696.     n_bits  = INIT_BITS;        /* number of bits/code            */
  1697.     maxbits = BITS;            /* user settable max # bits/code    */
  1698.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  1699.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  1700.  
  1701.     for ( code = 255; code >= 0; code-- ) {
  1702.     tab_prefixof(code) = 0;
  1703.     tab_suffixof(code) = (char_type)code;
  1704.     }
  1705.     free_ent = ((block_compress) ? FIRST : 256 );
  1706.  
  1707.     finchar = oldcode = getcode();
  1708.     if (oldcode == -1)          /* EOF already? */
  1709.     return;         /* Get out of here */
  1710.     oputc((char)finchar);       /* first code must be 8 bits = char */
  1711.     stackp = de_stack;
  1712.  
  1713.     while ((code = getcode()) > -1) {
  1714.     if ((code == CLEAR) && block_compress) {
  1715.         for (code = 255; code >= 0; code--)
  1716.         tab_prefixof(code) = 0;
  1717.         clear_flg = 1;
  1718.         free_ent = FIRST - 1;
  1719.         if ((code = getcode()) == -1)   /* O, untimely death! */
  1720.         break;
  1721.     }
  1722.     incode = code;
  1723.     /*
  1724.      * Special case for KwKwK string.
  1725.      */
  1726.     if (code >= free_ent) {
  1727.         *stackp++ = finchar;
  1728.         code = oldcode;
  1729.     }
  1730.  
  1731.     /*
  1732.      * Generate output characters in reverse order
  1733.      */
  1734.     while ( code >= 256 ) {
  1735.         *stackp++ = tab_suffixof(code);
  1736.         code = tab_prefixof(code);
  1737.     }
  1738.     *stackp++ = finchar = tab_suffixof(code);
  1739.  
  1740.     /*
  1741.      * And put them out in forward order
  1742.      */
  1743.     do
  1744.         oputc (*--stackp);
  1745.     while (stackp > de_stack);
  1746.  
  1747.     /*
  1748.      * Generate the new entry.
  1749.      */
  1750.     if ((code=free_ent) < maxmaxcode) {
  1751.         tab_prefixof(code) = (unsigned short)oldcode;
  1752.         tab_suffixof(code) = finchar;
  1753.         free_ent = code+1;
  1754.     }
  1755.     /*
  1756.      * Remember previous code.
  1757.      */
  1758.     oldcode = incode;
  1759.     }
  1760. }
  1761.  
  1762. code_int
  1763. getcode()
  1764. {
  1765.     /*
  1766.      * On the VAX, it is important to have the register declarations
  1767.      * in exactly the order given, or the asm will break.
  1768.      */
  1769.  
  1770.     register code_int code;
  1771.     static int offset = 0, size = 0;
  1772.     static char_type buf[BITS];
  1773.     register int r_off, bits;
  1774.     register char_type *bp = buf;
  1775.  
  1776.     if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  1777.     /*
  1778.      * If the next entry will be too big for the current code
  1779.      * size, then we must increase the size.  This implies reading
  1780.      * a new buffer full, too.
  1781.      */
  1782.     if ( free_ent > maxcode ) {
  1783.         n_bits++;
  1784.         if ( n_bits == maxbits )
  1785.         maxcode = maxmaxcode;    /* won't get any bigger now */
  1786.         else
  1787.         maxcode = MAXCODE(n_bits);
  1788.     }
  1789.     if ( clear_flg > 0) {
  1790.         maxcode = MAXCODE (n_bits = INIT_BITS);
  1791.         clear_flg = 0;
  1792.     }
  1793.     size = oread(buf, n_bits);
  1794.     if (size <= 0)
  1795.         return -1;            /* end of file */
  1796.     offset = 0;
  1797.     size = (size << 3) - (n_bits - 1);
  1798.     }
  1799.     r_off = offset;
  1800.     bits = n_bits;
  1801.  
  1802.     /*
  1803.      * Get to the first byte.
  1804.      */
  1805.     bp += (r_off >> 3);
  1806.     r_off &= 7;
  1807.     /* Get first part (low order bits) */
  1808.  
  1809.     code = (*bp++ >> r_off);
  1810.  
  1811.     bits -= (8 - r_off);
  1812.     r_off = 8 - r_off;        /* now, offset into code word */
  1813.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  1814.     if ( bits >= 8 ) {
  1815.         code |= *bp++ << r_off;
  1816.         r_off += 8;
  1817.         bits -= 8;
  1818.     }
  1819.     /* high order bits. */
  1820.     code |= (*bp & rmask[bits]) << r_off;
  1821.  
  1822.     offset += n_bits;
  1823.  
  1824.     return code;
  1825. }
  1826.  
  1827. SHAR_EOF
  1828. cat << \SHAR_EOF > Makefile
  1829.  
  1830. #   Makefile for backup
  1831.  
  1832. SYMS=    include:symbols.m
  1833. SYMC=    include:local/makesymbols.c
  1834. CFLAGS= +L +I$(SYMS)
  1835. LFLAGS= +Q
  1836. DD=    srcc:
  1837. OD=    T:
  1838.  
  1839. $(DD)backup:    backup.c
  1840.     cc $(CFLAGS) backup.c -o $(OD)backup.o
  1841.     ln +Q $(OD)backup.o -lsup32 -lc32 -o $(DD)backup
  1842.     delete $(OD)backup.o
  1843.  
  1844. $(SYMS):    $(SYMC)
  1845.     make -f include:local/Makefile
  1846.  
  1847. SHAR_EOF
  1848. cat << \SHAR_EOF > backup.doc
  1849.  
  1850.                    BACKUP.DOC
  1851.  
  1852.                  V2.01
  1853.  
  1854.                  3 November 1988
  1855.      (c)Copyright 1988, Matthew Dillon, All Rights Reserved
  1856.            Freely Distributable for non-profit only
  1857.            (this is the same document as backup.doc v2.00)
  1858.  
  1859.                   (I)
  1860.                 OVERVIEW
  1861.  
  1862.     Backup and Restore (same executable, just renamed) allow you to backup
  1863.     any directory tree with optional compression, and later extract all
  1864.     or part of the tree.  The protection, date, and file comment is saved
  1865.     with each file.
  1866.  
  1867.     SEE SECTION (6), FLOPICAL BACKUP, for options pertaining to backing
  1868.     up directly to floppies.
  1869.  
  1870.     LIMITATIONS:    When using -c (compress), the entire result of the
  1871.     compressed file must fit into memory.  Any files (after compression,
  1872.     if any) larger than a floppy when backing up to floppies cannot be
  1873.     handled yet.
  1874.  
  1875.  
  1876.                   (I)
  1877.                   INSTALLATION
  1878.  
  1879.     Copy the (1) executable to your C: directory twice, naming one
  1880.     'Backup' and the other 'Restore'.  The program looks at the first
  1881.     character of its name to determine whether the default is to backup
  1882.     or restore.  If you don't have the space, all is not lost ... you
  1883.     simply need to specify backup or restore explicitly with the options
  1884.     (-b or -r).
  1885.  
  1886.                    (2)
  1887.                  EXOTIC FEATURES
  1888.  
  1889.     Backup does not write directory trees which contain no files.  Thus,
  1890.     when doing incremental backups on a large hard disk, the structure of
  1891.     directory sub-trees which have no new files in them will not be
  1892.     written.  So if you only modified a couple of files since the last
  1893.     backup, there won't be 50K of structure-overhead.
  1894.  
  1895.     You can specify compression (-c) in the backup.  All files are
  1896.     compressed (there must be enough RAM to hold the largest file in
  1897.     its compressed state).  Those files which would turn out larger after
  1898.     compression than before are NOT compressed.  Certain file suffixes
  1899.     cause the compression attempt to be skipped entire:  .Z, .ARC, and .ZOO
  1900.     files
  1901.  
  1902.       IT IS SUGGESTED YOU USE THE COMPRESSION FEATURE EVEN THOUGH IT
  1903.       SLOWS DOWN THE BACKUP.  The resulting backup file will be
  1904.       significantly reduced in size.  Even though a full backup will
  1905.       take a long time, you only do that every once in a while and
  1906.       as incremental backups are shorter, they take much less time.
  1907.  
  1908.     'Pick' patterns are supported (backup only paths which match the
  1909.     specified patterns), and 'Discard' patterns are supported (do not backup
  1910.     paths which match the specified patterns).    Discard patterns override
  1911.     Pick patterns.
  1912.  
  1913.                   (3)
  1914.                 OPTIONS
  1915.  
  1916.     Here is a list of Backup/Restore options.
  1917.  
  1918.     -A    ARCHIVE. (Backup) Causes the archive bit to be cleared
  1919.         on files being backed up.  (Protection bit -> 1)
  1920.  
  1921.         (Restore):  If specified, the archive bit is cleared on
  1922.         restored files.  Otherwise the archive bit will be set,
  1923.         causing the files to be backed up again on the next
  1924.         incremental backup.
  1925.  
  1926.     -U    UPDATE.  (Backup) Restricts the backup to only those files
  1927.         which have the archive bit set.  (Protection bit == 0)
  1928.  
  1929.     -b    BACKUP    (this is the default if the first character in
  1930.         the executable is a 'b')
  1931.  
  1932.     -r    RESTORE (this is the default if the first character in
  1933.         the executable is an 'r')
  1934.  
  1935.     -a    APPEND (Backup)     Cause the backup to be appended to
  1936.         the specified (-o) file rather than overwriting it.  Useful
  1937.         for incremental backups.
  1938.  
  1939.     -c    COMPRESS (Backup)   Cause all files to be compressed, if
  1940.         possible.  Restore automatically decompresses files which
  1941.         have been compressed.  This is the same algorithm used
  1942.         in the UNIX compress command.
  1943.  
  1944.         NO COMPRESSION WILL EVEN BE ATTEMPED ON FILES WITH THE
  1945.         FOLLOWING SUFFIXES: .Z .ARC .ZOO
  1946.  
  1947.     -f[#kb] Turn on backup fragmentation and specify the fragment size,
  1948.         default 800K (for backing up to floppies).  NOTE: Currently,
  1949.         files larger than the fragment size cannot be backed up!
  1950.  
  1951.         Note: a suffix is added to the file name w/ a sequence
  1952.         number, but each fragment is a complete backup file unto
  1953.         itself and may be restored out of order.
  1954.  
  1955.         Any numerical value specified is in K, i.e. -f800 == 800K
  1956.  
  1957.     -Fvol:    Add the volume (df0:, df1:, etc..) to the drive sequencing
  1958.         list.  The idea is to specify several -F options which are
  1959.         cycled through and prefix each fragment.  This also
  1960.         enables prompting... the program prompts whenever it
  1961.         switches to the next fragment.
  1962.  
  1963.         If -F is not specified at all and -f is, no prompting
  1964.         occurs.
  1965.  
  1966.     -s    Only display directories as we go along
  1967.  
  1968.     -S    Silent... don't display files or directories
  1969.  
  1970.     -v    Verbose... display those files which will NOT be backed
  1971.         up as well as those that will.
  1972.  
  1973.     -l/-t    (both do the same thing).  (Restore)   LIST the archive
  1974.         only, do not do an actual restore.
  1975.  
  1976.     -T    (Restore)   Restore ONLY the timestamp, comment, and
  1977.         protection fields.  This is incredibly useful to
  1978.         restore timestamp information to files that already
  1979.         exist.    NO files are overwritten or created on the
  1980.         destination volume(s).
  1981.  
  1982.     -n#    (Backup)    Sets the output buffer size, in KILOBYTES.
  1983.         Default is 64.
  1984.  
  1985.     -pPAT    (Backup)    Restrict the backup to files which match the
  1986.         specified pattern.  Up to 32 patterns may be specified.
  1987.  
  1988.         (Restore)   Extract only those files which match the
  1989.         specified pattern.
  1990.  
  1991.         NOTE:  The pattern is matched with the COMPLETE PATH as
  1992.         shown in the -t option.  '*' and '?' wildcarding is supported
  1993.  
  1994.     -dPAT    (Backup)    Do not backup files which match the specified
  1995.         pattern.   Up to 32 patterns may be specified.
  1996.  
  1997.         (Restore)   Do not extract files which match the specified
  1998.         pattern.
  1999.  
  2000.         NOTE: The pattern is matched with the COMPLETE PATH as
  2001.         shown in the -t option.  '*' and '?' wildcarding is supported.
  2002.  
  2003.     -oFILE    (Backup)    Specify the OUTPUT FILE for a backup.  IF NO
  2004.         OUTPUT FILE IS SPECIFIED, NO OUTPUT FILE IS CREATED.  I.E.
  2005.         you can take a second pass just to clear the archive bit.
  2006.  
  2007.         (Restore)   Specify the directory to place the restored
  2008.         directory tree.  (This overrides the volume the backup
  2009.         was saved from).  If no directory specified, the original
  2010.         volume used in the backup will be restored to.    If no
  2011.         volume was specified in the backup but rather a relative
  2012.         path was, the restore will be relative to the current
  2013.         directory.
  2014.  
  2015.                   (4)
  2016.               STANDARD METHOD OF BACKING UP
  2017.  
  2018.     Note that with combinations of -o, -A, and -U, you have many choices
  2019.     available to you when backing up files.  For hard disks, backups are
  2020.     normally done in two phases:
  2021.  
  2022.     -Once a month do a complete backup of your hard disk
  2023.     -Every day do a much smaller 'incremental' backup which backs
  2024.      up only those files which have been modified/created since the
  2025.      last backup.
  2026.  
  2027.     The master backup, plus the N incremental backups together
  2028.     reconstruct your disk up to the moment.  After a while the
  2029.     number of incremental backups will be so great (and messy),
  2030.     that you will want to do another complete backup and start
  2031.     again.
  2032.  
  2033.     IN THIS WAY, the COMPRESS option can be put to good use.  The
  2034.     incremental backups are usually small, and can be compressed
  2035.     relatively quickly.  The complete backup should also be compressed
  2036.     (-c in case you forgot) though this will take a much longer time...
  2037.     but then again the complete backup is not done every day.
  2038.  
  2039.     UPDATING THE ARCHIVE BIT ON THE FLY VERSES TAKING A SECOND PASS.
  2040.     Updating the archive bit involves writing to the disk.  For complete
  2041.     safety you probably do NOT want to update the archive bit while you
  2042.     are backing up the files in question.  The following two-pass method
  2043.     works well:
  2044.  
  2045.         (COMPLETE BACKUP)
  2046.  
  2047.     backup    -c -d"*.o" volume: -ooutput
  2048.     backup    -A volume:
  2049.  
  2050.         (INCREMENTAL BACKUP)
  2051.  
  2052.     backup -U -c -d"*.o" volume: -ooutput
  2053.     backup -A volume:
  2054.  
  2055.     The -d option is saying "Don't backup all those object modules I left
  2056.     laying around".
  2057.  
  2058.     The first command backs up only those files which have be modified
  2059.     or created but does NOT update the archive bit.  The second command
  2060.     updates the archive bit without doing anything else (no output file
  2061.     is specified and thus none is created).  The second command goes
  2062.     extremely quickly since files are not actually read.
  2063.  
  2064.     For your INCREMENTAL backups, risking modifying the archive bit while
  2065.     backing the files up is feasible,  Since very few files will be
  2066.     backed up (comparitively):
  2067.  
  2068.     backup -a -UA -c -d"*.o" volume: -ooutput
  2069.  
  2070.     In this case I use the -a option (append).  You might NOT want to do
  2071.     this and save the incremental backups as separate files.
  2072.  
  2073.  
  2074.                   (5)
  2075.               STANDARD METHOD OF RESTORING
  2076.  
  2077.     Restoring a backup to the original volume: (Restore or Backup -r)
  2078.  
  2079.     NOTE:  If the -A option is specified, restored files will have
  2080.     their Archive bit cleared.    If -A is NOT specified, files will have
  2081.     their archive bit set and will thus be re-backed up on the next
  2082.     incremental backup.
  2083.  
  2084.     NOTE:  When restoring files, remember that the incremental backups
  2085.     will have the newest modifications and should be specified LAST:
  2086.  
  2087.     Restore completebkfile incr1 incr2 incr3....
  2088.  
  2089.     Partial Restore using -p:
  2090.  
  2091.     Restore -pstuffIWant bkfile1 bkfile2 bkfile3...
  2092.  
  2093.     ARCHIVE LISTING:
  2094.  
  2095.     Restore -t bkfile1 bkfile2....
  2096.  
  2097.     NOTE:    Two 'sizes' are given in the listing.  The first
  2098.     is the # bytes the file takes up in the archive, the
  2099.     second is the actual size of the file.
  2100.  
  2101.  
  2102.                   (6)
  2103.               FLOPICAL BACKUP AND RESTORE
  2104.  
  2105.     There are two problems associated with floppy backup and restore:
  2106.  
  2107.     (1) A single file on the HD may be two big for a single floppy
  2108.     (2) It may take a lot of floppies to backup an HD
  2109.  
  2110.     Additionaly, one wants the following conveniences:
  2111.  
  2112.     (1) Be able to backup to a logical progression of (floppy) drives,
  2113.     inserted blank disks in while the system is working on other
  2114.     drives.
  2115.  
  2116.     (2) Be able to restore the same way
  2117.  
  2118.     (3) If one or more floppies is destroyed be able to restore from the
  2119.     remaining floppies.
  2120.  
  2121.         Currently, you can specify which devices to cycle through
  2122.         with the -F option (-Fdf0: -Fdf1: -Fdf2:), but BACKUP will
  2123.         always prompt you before continuing.  Since it uses the
  2124.         console device, you can specify the yes response as many
  2125.         times as you have floppies in ready drives.
  2126.  
  2127.         Currently, files larger than the specified -f size (800K
  2128.         default) cannot be handled if using -f/-F ... However, by
  2129.         enabling compression larger files can still fit.
  2130.  
  2131.         Currently, the entire compressed result of a file must be
  2132.         able to fit into memory during the backup.
  2133.  
  2134.  
  2135.                    ***
  2136.  
  2137.     BACKUP.    Specify the -f option and then -Fvol: for each floppy
  2138.     drive (in the order you want) to backup to.  Example:
  2139.  
  2140.     -f -Fdf0: -Fdf1:
  2141.  
  2142.     (Also keep in mind all the options listed in sections (3), (4), & (5))
  2143.     Currently, you must have PRE-FORMATTED all your backup disks since the
  2144.     backup/restore works through normal files.    The system will prompt for
  2145.     readyness every time it completes a section.
  2146.  
  2147.     The backup process never deletes files, only creates or overwrites
  2148.     them.  Thus, accidently sticking in a non-blank or incorrect backup
  2149.     disk will probably result in a disk-full requester.... not Fatal, though
  2150.     inconvenient.
  2151.  
  2152.     You must still specify the -o option to name the output file, which will
  2153.     be prefixed with the next -F volume in sequence and suffixed with the
  2154.     sequence number. (.nn)  The disk labels for your floppies may all be
  2155.     the same.
  2156.  
  2157.     EXAMPLE:
  2158.  
  2159.     backup    -c -d"*.o" -f -Fdf0: -Fdf1: -Fdf2: volume: -oxxbak
  2160.     backup    -A volume:
  2161.  
  2162.     NOTE:    You do NOT specifiy a volume prefix in the -o option ..
  2163.     those specified by -F are automatically cycled through as the
  2164.     prefix.
  2165.  
  2166.     * If your hard disk has enough space on it I suggest you backup to an
  2167.       alternate partition using only -f (not -F which forces user prompts),
  2168.       then copy the chunks to floppies after the entire backup has
  2169.       completed.
  2170.  
  2171.                    ***
  2172.  
  2173.     RESTORE.    Restore works the same way.  EACH DISK IS INDEPENDANT!    You
  2174.     may insert disks in any order to be restored.  Simply execute the
  2175.     standard restore command in section (5) for each floppy.
  2176.  
  2177.     Destroyed disks may be skipped.  Currently, no support for partially
  2178.     restored disks exists... i.e. the archive has be clean.
  2179.  
  2180.  
  2181.  
  2182. SHAR_EOF
  2183. #    End of shell archive
  2184. exit 0
  2185. -- 
  2186. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2187. Have five nice days.
  2188.